﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Checkpoint2XNA.Models;
using Microsoft.Xna.Framework;

namespace Checkpoint2XNA.Utilities
{
    public class QuadTreeNode
    {
        public QuadTreeNode()
        {
            GridIndex = -1;
        }

        public QuadTreeNode(BoxStruct rect, int grid)
        {
            Rect = rect;
            GridIndex = grid;
        }

        public QuadTreeNode(params QuadTreeNode[] children)
        {
            GridIndex = -1;
            Rect = new BoxStruct { Min = children[0].Rect.Min, Max = children[children.Length - 1].Rect.Max };
            Children = children;
        }

        public QuadTreeNode[] Children { get; set; }
        public BoxStruct Rect { get; set; }

        public int GridIndex { get; set; }

        public bool Empty()
        {
            bool empty = true;

            if (Children != null)
            {
                for (int i = 0; i < Children.Length; i++)
                {
                    if (!Children[i].Empty())
                    {
                        empty = false;
                        break;
                    }
                }
            }
            else if (GridIndex >= 0)
            {
                if (QuadTree.grid[GridIndex] != null)
                    empty = false;
            }

            return empty;
        }

        //Perform recursive depth-first search by closeness of collision point on colliding children
        public Tuple<Model3D, double> RayCollide(Vector3 origin, Vector3 ray, Vector3 invRay)
        {

            Tuple<Model3D, double> closest = null;

            //It's assumed that if the node has a model, it is a leaf with no children
            //So this is either-or -- model or children -- collision check
            if (GridIndex >= 0 && QuadTree.grid[GridIndex] != null)
            {
                var t = QuadTree.grid[GridIndex].RayCollide(origin, ray);
                if (t > 0)
                {
                    closest = Tuple.Create(QuadTree.grid[GridIndex], t);
                }
            }
            else
            {

                var colliding = new List<Tuple<QuadTreeNode, double>>();
                for (int i = 0; i < Children.Length; i++)
                {
                    double t = -1;
                    if (!Children[i].Empty() && (t = Collisions.BoxCollide(origin, ray, invRay, Children[i].Rect)) >= 0)
                    {
                        colliding.Add(Tuple.Create(Children[i], t));
                    }
                }

                colliding.OrderBy(q => q.Item2);

                Tuple<Model3D, double> temp = null;
                for (int i = 0; i < colliding.Count; i++)
                {
                    if ((temp = colliding[i].Item1.RayCollide(origin, ray, invRay)) != null)
                    {
                        if (closest == null || temp.Item2 < closest.Item2)
                        {
                            closest = temp;
                        }
                    }
                }
            }

            return closest;
        }
    }
}
